package org.adorsys.aderp.aderplogin.xchange;

import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.adorsys.aderp.aderplogin.domain.AderpPersonRef;
import org.adorsys.aderp.aderplogin.repository.AderpPersonRefRepository;
import org.adorsys.aderp.aderplogin.service.AderpPersonRefService;
import org.adorsys.aderp.jpa.api.audit.ModifMode;
import org.adorsys.aderp.jpa.api.xchange.DataRequest;
import org.adorsys.aderp.jpa.api.xchange.DataResponse;
import org.adorsys.aderp.jpa.api.xchange.DataView;
import org.adorsys.aderp.jpa.api.xchange.MapPage;
import org.adorsys.aderp.jpa.api.xchange.SimpleAuditRecord;
import org.adorsys.aderp.jpa.api.xchange.XchangeAuditRecordService;
import org.adorsys.aderp.jpa.api.xchange.XchangeRecordService;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

public class AderpPersonRefSynchronizer {
	
	@Resource(name="orgaPersonXChangeRecordService")
	private XchangeRecordService orgaPersonXChangeRecordService;
	
	@Resource(name="orgaPersonXchangeAuditRecordService")
	private XchangeAuditRecordService orgaPersonXchangeAuditRecordService;
	
	@Resource
	private AderpPersonRefService aderpPersonRefService;
	
	@Resource
	private AderpPersonRefRepository aderpPersonRefRepository;
	
	private Date lastSynch;
	
	private DataView dataView = OrgaPersonDataView.getOrgaPersonDataView();
	
	@Resource
	private AderpPersonRefSynchronizer aderpPersonRefSynchronizer;
	
	public void synch(){
		try {
			if(lastSynch==null) lastSynch=aderpPersonRefRepository.getLastUpdate();
			if(lastSynch==null){
				lastSynch = DateUtils.addYears(new Date(), -1);
			}
			int positionIndex = 0;
			Pageable pageable = new PageRequest(positionIndex, 10);
			MapPage result = orgaPersonXchangeAuditRecordService.loadAuditRecord(lastSynch, pageable);
			consumeData(result);
			while(result.hasNextPage()){
				positionIndex +=result.getSize();
				result = orgaPersonXchangeAuditRecordService.loadAuditRecord(lastSynch, pageable);
				consumeData(result);
			}	
		} catch(Exception ex){
			String message = ex.getMessage();
			Assert.notNull(ex,message);
		}
	}
	
	private void consumeData(MapPage page){
		List<Map<String,String>> content = page.getContent();
		for (Map<String, String> data : content) {
			SimpleAuditRecord auditRecord = new SimpleAuditRecord(data);
			String recordKey = auditRecord.getRecordKey();
			List<AderpPersonRef> found = aderpPersonRefRepository.findByExternalRef(recordKey);
			if(!found.isEmpty()) continue;// record processed

			String personNumber = auditRecord.getEntityKey();
			
			ModifMode modifMode = auditRecord.getModifMode();
			
			if(ModifMode.DELETED==modifMode){
				aderpPersonRefSynchronizer.deleteAderpPersonRef(personNumber);
				continue;
			}
			
			DataRequest dataRequest = new DataRequest();
			dataRequest.setDataView(dataView);
			dataRequest.setEntityKey(auditRecord.getEntityKey());
			dataRequest.setEntityName(auditRecord.getEntityName());
			DataResponse dataResponse = orgaPersonXChangeRecordService.loadEntity(dataRequest);
			Map<String, String> changes = dataResponse.getEntityData();

			switch (modifMode) {
				case CREATED:
					aderpPersonRefSynchronizer.createAderpPersonRef(personNumber, changes, auditRecord);
					break;
				case CHANGED:
					aderpPersonRefSynchronizer.changeAderpPersonRef(personNumber,changes, auditRecord);
				default:
					break;
			}
		}
		
	}
	
	@Transactional
	public void deleteAderpPersonRef(String personNumber) {
		AderpPersonRef ad = aderpPersonRefService.findByPersonNumber(personNumber);
		if(ad==null) return;
		aderpPersonRefService.deleteAderpPersonRef(ad);
	}

	@Transactional
	public void changeAderpPersonRef(String personNumber, Map<String, String> changes, SimpleAuditRecord auditRecord) {
		AderpPersonRef ad = aderpPersonRefService.findByPersonNumber(personNumber);
		if(ad==null) {
			createAderpPersonRef(personNumber, changes, auditRecord);// missing record
			return;
		}
		
		synchADerpPersonRef(ad, changes, auditRecord);
		aderpPersonRefService.saveAderpPersonRef(ad);		
	}

	@Transactional
	public void createAderpPersonRef(String personNumber, Map<String, String> changes, SimpleAuditRecord auditRecord) {
		AderpPersonRef ad = aderpPersonRefService.findByPersonNumber(personNumber);
		if(ad!=null) return;
		
		ad = new AderpPersonRef();
		ad.setPersonNumber(personNumber);
		
		synchADerpPersonRef(ad, changes, auditRecord);
		
		aderpPersonRefService.saveAderpPersonRef(ad);
	}
	
	private void synchADerpPersonRef(AderpPersonRef ad, Map<String, String> changes,
			SimpleAuditRecord auditRecord){
		ad.setEmail(changes.get(OrgaPersonDataView.EMAIL_MAP_KEY));
		ad.setFirstName(changes.get(OrgaPersonDataView.FIRSTNAME_MAP_KEY));
		ad.setGenderKey(changes.get(OrgaPersonDataView.GENDERKEY_MAP_KEY));
		ad.setLastName(changes.get(OrgaPersonDataView.LASTNAME_MAP_KEY));
		String dobString = changes.get(OrgaPersonDataView.DOB_MAP_KEY);
		if(dobString!=null){
			ad.setDob(new Date(Long.parseLong(dobString)));
		}
		
		ad.setLastUpdate(auditRecord.getModifOn());
		ad.setExternalRef(auditRecord.getRecordKey());
	}	
}
